﻿Imports System.Drawing
Imports WindowsHookLib
Imports System.Windows.Forms
Imports System.Collections.Generic
Imports GameEx
Imports AForge.Controls
Imports AForge
Imports System.Runtime.InteropServices
Imports WindowsHookLib.KeyboardHook


Public Class QLPicker

    Private _ShowHandles As Boolean = False
    Public Property ShowHandles() As Boolean
        Get
            Return _ShowHandles
        End Get
        Set(ByVal value As Boolean)
            _ShowHandles = value
        End Set
    End Property

    Private _RClickClose As Boolean = False
    Public Property RightClickClose() As Boolean
        Get
            Return _RClickClose
        End Get
        Set(ByVal value As Boolean)
            _RClickClose = value
        End Set
    End Property

    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Private Shared Function GetAsyncKeyState(ByVal vkey As System.Windows.Forms.Keys) As Short
        'Nothing
    End Function

#Region "props"

    Private _delonce As Integer
    Public Property QLDelOnceKey() As Integer
        Get
            Return _delonce
        End Get
        Set(ByVal value As Integer)
            _delonce = value
        End Set
    End Property

    Private _delalways As Integer
    Public Property QLDelAlwaysKey() As Integer
        Get
            Return _delalways
        End Get
        Set(ByVal value As Integer)
            _delalways = value
        End Set
    End Property

    Private _keeponce As Integer
    Public Property QLKeepOnceKey() As Integer
        Get
            Return _keeponce
        End Get
        Set(ByVal value As Integer)
            _keeponce = value
        End Set
    End Property

    Private _keepalways As Integer
    Public Property QLKeepAlwaysKey() As Integer
        Get
            Return _keepalways
        End Get
        Set(ByVal value As Integer)
            _keepalways = value
        End Set
    End Property

    Private _select As Integer
    Public Property QLSelectKey() As Integer
        Get
            Return _select
        End Get
        Set(ByVal value As Integer)
            _select = value
        End Set
    End Property

    Private _picked As String
    Public Property Picked() As String
        Get
            Return _picked
        End Get
        Set(ByVal value As String)
            _picked = value
        End Set
    End Property

#End Region

    Public WithEvents kHook As New WindowsHookLib.KeyboardHook

    Public WithEvents mHook As New WindowsHookLib.MouseHook

    Dim mousex As Integer
    Dim mousey As Integer
    Dim drag As Boolean = False

    Public GP1 As Joystick
    Public Event GPButtonDown(ByVal GPadEventType As String, ByVal Button As Integer)
    Public Event GPDpadDown(ByVal GPadEventType As String, ByVal Dpad As Integer)
    Public Event GPDpadNull(ByVal GPadEventType As String, ByVal Dpad As Integer)
    Public OldDPadValue As Integer
    Public GamePadAvail As Boolean = False

    Public returnval As String = "nuttin"

    Public KeyCodes As New List(Of Integer)

    Public keypressed As Integer = -1

    Public foreThread As UInteger = Nothing
    Public appThread As UInteger = Nothing

    Public backform As New BGForm

    Private Sub QLPicker_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing

        backform.Close()
        backform.Dispose()

        TopMostTimer.Stop()

        kHook.RemoveHook()
        My.Settings._pickPos = Me.Location
        My.Settings._pickSize = Me.Size
        My.Settings.Save()

        ' Plugin.BroadcastMode = False

        Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Quicklaunch Closing.")
        Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Size @ close: " & My.Settings._pickSize.ToString)
        Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Pos @ close: " & My.Settings._pickPos.ToString)
    End Sub

    <DllImport("user32.dll")> _
    Private Shared Function SetActiveWindow(handle As IntPtr) As IntPtr
    End Function
    Private Const WM_ACTIVATE As Integer = 6
    Private Const WA_INACTIVE As Integer = 0

    Private Const MouseEventLeftDown As UInt32 = &H2
    Private Const MouseEventLeftUp As UInt32 = &H4

    <DllImport("user32.dll")> _
    Private Shared Sub mouse_event(dwFlags As UInt32, dx As UInt32, dy As UInt32, dwData As UInt32, dwExtraInfo As IntPtr)
    End Sub

    Private Sub AlignForms() Handles Me.Move, Me.SizeChanged, Me.Layout

        backform.Location = Me.Location
        backform.Size = Me.Size

        If drag = False Then
            PushFormToTop(backform)
            PushFormToTop(Me)

        End If

    End Sub




    Private Sub QLPicker_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        DoubleBuffered = True
        Me.TransparencyKey = Color.FromArgb(1, 2, 4)
        Me.BackColor = Color.FromArgb(1, 2, 4)
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        Me.Size = My.Settings._pickSize
        Me.Location = My.Settings._pickPos
        Me.Opacity = 1

        If _ShowHandles Then
            MovePB.Visible = True
            ClosePB.Visible = True
            ResizePB.Visible = True
        End If

        ' Me.SetStyle(ControlStyles.Selectable, False)

        Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Prompt process started....: ")

        ' Plugin.BroadcastMode = True

        Initialise()

        backform.Show()
        AlignForms()

        ''SendLeftClick()
        ''MoveMouse(5, 5)
        ''LeftClick()
        'Button1.PerformClick()

        ''Me.BringToFront()
        'Me.TopMost = True
        'Me.TopMost = False
        'Me.Activate()#

        ' force window to have focus
        foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero)
        appThread = GetCurrentThreadId()
        Const SW_SHOW As UInteger = 5
        If foreThread <> appThread Then
            AttachThreadInput(foreThread, appThread, True)
            BringWindowToTop(Me.Handle)
            ShowWindow(Me.Handle, SW_SHOW)
            AttachThreadInput(foreThread, appThread, False)
        Else
            BringWindowToTop(Me.Handle)
            ShowWindow(Me.Handle, SW_SHOW)
        End If

        PushFormToTop(backform)
        PushFormToTop(Me)

        Me.Activate()

        TopMostTimer.Start()


    End Sub


    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function GetWindowThreadProcessId(hWnd As IntPtr, ByRef lpdwProcessId As UInteger) As UInteger
    End Function

    ' When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
    <DllImport("user32.dll")> _
    Private Shared Function GetWindowThreadProcessId(hWnd As IntPtr, ProcessId As IntPtr) As UInteger
    End Function

    <DllImport("kernel32.dll")> _
    Private Shared Function GetCurrentThreadId() As UInteger
    End Function

    ''' <summary>The GetForegroundWindow function returns a handle to the foreground window.</summary>
    <DllImport("user32.dll")> _
    Private Shared Function GetForegroundWindow() As IntPtr
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function AttachThreadInput(idAttach As UInteger, idAttachTo As UInteger, fAttach As Boolean) As Boolean
    End Function

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function BringWindowToTop(hWnd As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function BringWindowToTop(hWnd As HandleRef) As Boolean
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function ShowWindow(hWnd As IntPtr, nCmdShow As UInteger) As Boolean
    End Function

    Public Function IsOnScreen(ByVal form As Form) As Boolean
        ' Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Check Form on Screen....")
        Dim screens() As Screen = Screen.AllScreens
        For Each scrn As Screen In screens
            ' Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Screen X,Y: " & scrn.Bounds.X & ", " & scrn.Bounds.Y)
            ' Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Screen W,H: " & scrn.Bounds.Width & ", " & scrn.Bounds.Height)
            ' Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: ------")
            Dim formRectangle As Rectangle = New Rectangle(form.Left, form.Top, form.Width, form.Height)
            If scrn.WorkingArea.Contains(formRectangle) Then
                ' Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Form in bounds of this screen. Return True.")
                Return True
            End If
        Next
        ' Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Form not in the bounds of any screen. Return False.")
        Return False
    End Function

    Public Sub Initialise()
        ''
        MidPB.Image = My.Resources.QLCenter

        ' kHook.InstallHook()

        Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Keyhook state after InstallHook: " & kHook.State.ToString)
        Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Debug Checked in Config: " & My.Settings.ConfigDebug.ToString)

        If My.Settings.ConfigDebug = True Then
            '  Input.Visible = True
        End If

        InitGamepads()

        If GamePadAvail Then
            GPTimer.Start()
        End If

        'DX keyhook
        KeyCodes.Add(_delalways)
        KeyCodes.Add(_delonce)
        KeyCodes.Add(_keepalways)
        KeyCodes.Add(_keeponce)
        KeyCodes.Add(_select)
        KBPoll.Start()



    End Sub


    Private Sub InitGamepads()

        ' cflog.echo("Checking for Gamepads:")
        Dim devices As List(Of Joystick.DeviceInfo) = Joystick.GetAvailableDevices()
        If devices.Count < 1 Then
            '  cflog.echo("No Gamepads plugged in")
            GamePadAvail = False
        Else
            ' cflog.echo("Gamepads Found:")
            For Each di As Joystick.DeviceInfo In devices
                'cflog.echo("Device: " & di.ID & ", " & di.Name & ", " & di.Axes & ", " & di.Buttons)
            Next
            GP1 = New Joystick(0)
            GamePadAvail = True
        End If
    End Sub

    Private Sub KBPoll_Tick(sender As Object, e As EventArgs) Handles KBPoll.Tick
        Dim kc As New KeysConverter
        Dim key As Boolean
        Dim setdown As Boolean = False

        If keypressed <> -1 Then
            key = GetAsyncKeyState(keypressed)
            If key = False Then
                khook_keyup()
                keypressed = -1
            End If
        End If

        For Each keypress As Integer In KeyCodes
            key = GetAsyncKeyState(keypress)
            If key = True Then
                'Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Keypoll captured: " & keypress & "(" & kc.ConvertToString(keypress) & ")")
                If keypress = _select Then
                    '
                Else
                    khook_keyup()
                End If
                kHook_KeyDown(keypress)
                keypressed = keypress
            End If
        Next
        'If setdown = False Then khook_keyup()
    End Sub

    Private Sub kHook_KeyDown(KeyCode As Integer)

        ' Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: KeyDown: " & KeyCode & "(" & kc.ConvertToString(KeyCode) & ")")

        Select Case KeyCode

            Case _delalways
                MidPB.Image = My.Resources.QLLEFT
                DelAlwaysPB.BackColor = Color.Yellow
                returnval = "DelAlways"
            Case _delonce
                MidPB.Image = My.Resources.QLDOWN
                DelThisPB.BackColor = Color.Yellow
                returnval = "DelOnce"
            Case _keepalways
                MidPB.Image = My.Resources.QLRIGHT
                KeepAlwaysPB.BackColor = Color.Yellow
                returnval = "KeepAlways"
            Case _keeponce
                MidPB.Image = My.Resources.QLUP
                KeepThisPB.BackColor = Color.Yellow
                returnval = "KeepOnce"
            Case _select
                ReturnValue(Nothing, Nothing)

        End Select

    End Sub

    Private Sub khook_keyup()

        Dim kc As New KeysConverter
        '  Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: KeyUp: " & e.KeyCode & "(" & kc.ConvertToString(e.KeyCode) & ")")

        MidPB.Image = My.Resources.QLCenter
        DelAlwaysPB.BackColor = Color.Transparent
        DelThisPB.BackColor = Color.Transparent
        KeepAlwaysPB.BackColor = Color.Transparent
        KeepThisPB.BackColor = Color.Transparent
        returnval = "NoneSelected"

    End Sub

    Private Sub GamePadFire(ByVal type As String, ByVal args As Integer) Handles Me.GPButtonDown, Me.GPDpadDown

        Plugin.GEmvoy.WriteGVEntry("Gamepad event fired: " & type & "- " & args)
        Plugin.GEmvoy.WriteGVEntry("QLGPSel: " & GEmvoy.Setts.QLGPSel)

        If type = "ButtonDown" Then
            If args = GEmvoy.Setts.QLGPSel Then
                ReturnValue(Nothing, Nothing)
            End If
        End If

        If type = "DPadDown" Then
            Select Case args
                Case 270
                    MidPB.Image = My.Resources.QLLEFT
                    DelAlwaysPB.BackColor = Color.Yellow
                    returnval = "DelAlways"
                Case 180
                    MidPB.Image = My.Resources.QLDOWN
                    DelThisPB.BackColor = Color.Yellow
                    returnval = "DelOnce"
                Case 90
                    MidPB.Image = My.Resources.QLRIGHT
                    KeepAlwaysPB.BackColor = Color.Yellow
                    returnval = "KeepAlways"
                Case 0
                    MidPB.Image = My.Resources.QLUP
                    KeepThisPB.BackColor = Color.Yellow
                    returnval = "KeepOnce"
            End Select
        End If


    End Sub



    Private Sub DPad_Nulled(ByVal type As String, ByVal args As Integer) Handles Me.GPDpadNull
        MidPB.Image = My.Resources.QLCenter
        DelAlwaysPB.BackColor = Color.Transparent
        DelThisPB.BackColor = Color.Transparent
        KeepAlwaysPB.BackColor = Color.Transparent
        KeepThisPB.BackColor = Color.Transparent
        returnval = "NoneSelected"
    End Sub

    Private Sub Highlight_mouseover(sender As Object, e As EventArgs) Handles DelAlwaysPB.MouseEnter,
        DelThisPB.MouseEnter, KeepAlwaysPB.MouseEnter, KeepThisPB.MouseEnter

        sender.backcolor = Color.Yellow
        Select Case sender.name
            Case "DelAlwaysPB"
                MidPB.Image = My.Resources.QLLEFT
                DelAlwaysPB.BackColor = Color.Yellow
                returnval = "DelAlways"
            Case "DelThisPB"
                MidPB.Image = My.Resources.QLDOWN
                DelThisPB.BackColor = Color.Yellow
                returnval = "DelOnce"
            Case "KeepAlwaysPB"
                MidPB.Image = My.Resources.QLRIGHT
                KeepAlwaysPB.BackColor = Color.Yellow
                returnval = "KeepAlways"
            Case "KeepThisPB"
                MidPB.Image = My.Resources.QLUP
                KeepThisPB.BackColor = Color.Yellow
                returnval = "KeepOnce"
        End Select

    End Sub

    Private Sub Highlight_mouseclick(sender As Object, e As EventArgs) Handles DelAlwaysPB.MouseClick,
    DelThisPB.MouseClick, KeepAlwaysPB.MouseClick, KeepThisPB.MouseClick

        ReturnValue(Nothing, Nothing)

    End Sub



    Private Sub Highlight_mouseleave(sender As Object, e As EventArgs) Handles DelAlwaysPB.MouseLeave,
    DelThisPB.MouseLeave, KeepAlwaysPB.MouseLeave, KeepThisPB.MouseLeave

        sender.backcolor = Color.Transparent
        MidPB.Image = My.Resources.QLCenter
        returnval = "NoneSelected"

    End Sub

    Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MovePB.MouseDown
        ' Debug.WriteLine("Mouse Down")
        '  Debug.WriteLine(sender.ToString)
        drag = True
        mousex = Windows.Forms.Cursor.Position.X - Me.Left
        mousey = Windows.Forms.Cursor.Position.Y - Me.Top
    End Sub

    Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MovePB.MouseMove
        ' Debug.WriteLine("Mouse Move")
        If drag Then
            Me.Top = Windows.Forms.Cursor.Position.Y - mousey
            Me.Left = Windows.Forms.Cursor.Position.X - mousex
        End If
    End Sub

    Private Sub Form1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MovePB.MouseUp
        '  Debug.WriteLine("Mouse Up")
        drag = False
        'My.Settings._Location = Me.Location
        'My.Settings.Save()

    End Sub

    Private Sub Resize_MD(sender As Object, e As EventArgs) Handles ResizePB.MouseDown
        drag = True
        'bottom left co-ordinates:
        mousex = Me.Left
        mousey = Me.Top
    End Sub

    Private Sub Resize_MM(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ResizePB.MouseMove
        ' Debug.WriteLine("Mouse Move")
        If drag Then
            Me.Width = Windows.Forms.Cursor.Position.X - mousex
            Me.Height = Windows.Forms.Cursor.Position.Y - mousey
        End If
    End Sub

    Private Sub Resize_MU(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ResizePB.MouseUp
        drag = False
        'SendLeftClick()
        'LeftClick()
    End Sub

    Public Sub ReturnValue(ByVal sender As System.Object, ByVal e As System.EventArgs)

        If returnval = "NoneSelected" Then Return

        _picked = returnval

        Plugin.GEmvoy.WriteGVEntry(">> QLPrompt: Action Picked: " & returnval)

        Me.DialogResult = System.Windows.Forms.DialogResult.OK
        ' Me.Close()
    End Sub



    Private Sub PollGamePad() Handles GPTimer.Tick

        Dim PresGPStaus As Joystick.Status = GP1.GetCurrentStatus()

        If PresGPStaus.Buttons <> 0 Then
            RaiseEvent GPButtonDown("ButtonDown", PresGPStaus.Buttons)
        End If

        If PresGPStaus.PointOfView <> OldDPadValue And
            PresGPStaus.PointOfView = -1 Then
            RaiseEvent GPDpadNull("DPadNull", PresGPStaus.PointOfView)
        End If

        If PresGPStaus.PointOfView <> OldDPadValue And
            PresGPStaus.PointOfView <> -1 Then
            RaiseEvent GPDpadDown("DPadDown", PresGPStaus.PointOfView)
        End If

        OldDPadValue = PresGPStaus.PointOfView

    End Sub

    Public Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
    Public Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long
    Public Declare Function GetCursorPos Lib "user32" (ByVal lpPoint As POINTAPI) As Long
    Public Const MOUSEEVENTF_LEFTDOWN = &H2
    Public Const MOUSEEVENTF_LEFTUP = &H4
    Public Const MOUSEEVENTF_MIDDLEDOWN = &H20
    Public Const MOUSEEVENTF_MIDDLEUP = &H40
    Public Const MOUSEEVENTF_RIGHTDOWN = &H8
    Public Const MOUSEEVENTF_RIGHTUP = &H10
    Public Const MOUSEEVENTF_MOVE = &H1
    Public Structure POINTAPI
        Public x As Long
        Public y As Long
    End Structure
    Public Function GetX() As Long
        Dim n As POINTAPI
        GetCursorPos(n)
        GetX = n.x
    End Function
    Public Function GetY() As Long
        Dim n As POINTAPI
        GetCursorPos(n)
        GetY = n.y

    End Function
    Public Sub LeftClick()
        LeftDown()
        LeftUp()
    End Sub
    Public Sub LeftDown()
        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
    End Sub
    Public Sub LeftUp()
        mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
    End Sub
    Public Sub MiddleClick()
        MiddleDown()
        MiddleUp()
    End Sub
    Public Sub MiddleDown()
        mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0)
    End Sub
    Public Sub MiddleUp()
        mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0)
    End Sub
    Public Sub RightClick()
        RightDown()
        RightUp()
    End Sub
    Public Sub RightDown()
        mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)
    End Sub
    Public Sub RightUp()
        mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)
    End Sub
    Public Sub MoveMouse(ByVal xMove As Long, ByVal yMove As Long)
        mouse_event(MOUSEEVENTF_MOVE, xMove, yMove, 0, 0)
    End Sub
    Public Sub SetMousePos(ByVal xPos As Long, ByVal yPos As Long)
        SetCursorPos(xPos, yPos)
    End Sub

    <DllImport("user32.dll")> _
    Public Shared Function SetWindowPos(hWnd As IntPtr, hWndInsertAfter As IntPtr, X As Integer, Y As Integer, cx As Integer, cy As Integer, uFlags As UInteger) As Boolean
    End Function

    Private Sub PushFormToTop(FormForTop As Form)
        'Debug.WriteLine(vbCr & "++++++++ Push Form Topmost Triggered +++++++++")
        'Debug.WriteLine("FORM: " & FormForTop.ToString)
        Try
            Dim HWND_TOPMOST As New IntPtr(-1)
            Dim SWP_NOACTIVATE As UInteger = &H10
            Dim SWP_NOMOVE As UInteger = &H2
            Dim SWP_NOSIZE As UInteger = &H1
            SetWindowPos(FormForTop.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE)
        Catch ex As Exception
            'MMLog.Log_Data("Error whilst push for to top: " & ex.Message)
        End Try

    End Sub



    Private Sub TopMostTimer_Tick(sender As Object, e As EventArgs) Handles TopMostTimer.Tick
        Try
            foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero)
            appThread = GetCurrentThreadId()
            Const SW_SHOW As UInteger = 5
            If GetForegroundWindow() <> Me.Handle Then
                Me.TopMost = True
                AttachThreadInput(foreThread, appThread, True)
                BringWindowToTop(Me.Handle)
                ShowWindow(Me.Handle, SW_SHOW)
                AttachThreadInput(foreThread, appThread, False)
                PushFormToTop(backform)
                PushFormToTop(Me)
                Me.Activate()
                AppActivate(CInt(Me.Handle))
            Else

            End If
        Catch
        End Try

    End Sub


    Private Sub ClosePB_Click(sender As Object, e As EventArgs) Handles ClosePB.Click
        If _ShowHandles Then
            Me.Close()
        End If
    End Sub

    Private Sub MovePB_Click(sender As Object, e As EventArgs) Handles MovePB.Click

    End Sub



    Private Sub PictureBox2_Click(sender As Object, e As EventArgs) Handles PictureBox2.Click
        If _ShowHandles = False Then
            MovePB.Visible = True
            ClosePB.Visible = True
            ResizePB.Visible = True
            _ShowHandles = True
        Else
            MovePB.Visible = False
            ClosePB.Visible = False
            ResizePB.Visible = False
            _ShowHandles = False
        End If
    End Sub

End Class